package util

import (
	"fmt"
	"log"
	"log/slog"
	"os"
	"os/signal"
	"runtime"
	"runtime/debug"
	"strconv"
	"syscall"
)

var LOG_LEVEL = struct {
	DEBUG string
	ERROR string
	WARN  string
	INFO  string
}{DEBUG: "debug", ERROR: "error", WARN: "warn", INFO: "info"}

var SYSTEM_LOG_LEVEL = (func() string {
	value := os.Getenv("SYSTEM_LOG_LEVEL")
	if value == "" {
		value = LOG_LEVEL.ERROR
	}
	return value
})()

func SetLog(level_str string) (level slog.Level) {

	switch level_str {
	case LOG_LEVEL.DEBUG:
		level = slog.LevelDebug
	case LOG_LEVEL.ERROR:
		level = slog.LevelError
	case LOG_LEVEL.WARN:
		level = slog.LevelWarn
	case LOG_LEVEL.INFO:
		level = slog.LevelInfo
	}

	slog.SetLogLoggerLevel(level)

	return
}

var SYSTEM_MEM_LIMIT = (func() int {
	value, _ := strconv.Atoi(os.Getenv("SYSTEM_MEM_LIMIT"))
	if value < 1024 {
		value = 1024
	}
	return value
})()

func SetMen(size_gb int) {

	if size_gb <= 1 {
		size_gb = 1
	}

	debug.SetMemoryLimit(int64(size_gb) * 1024 * 1024 * 1024)
}

var SYSTEM_CPU_LIMIT = (func() int {
	value, _ := strconv.Atoi(os.Getenv("SYSTEM_CPU_LIMIT"))
	if value < 1 {
		value = 1
	}
	return value
})()

func SetCpu(number int) {

	runtime.GOMAXPROCS(number)
}

func Setup(object func() (error, error)) {

	if warn, err := object(); err != nil {

		log.Println(err.Error())

		os.Exit(1)

	} else if warn != nil {

		log.Println(warn.Error())
	}
}

func Exit(handle func()) {

	signals := make(chan os.Signal, 1)
	signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)

	<-signals

	if handle != nil {
		handle()
	}

	os.Exit(0)
}

func Recover(err *error) {

	if info := recover(); info != nil {

		*err = fmt.Errorf("[RECOVER] %s", fmt.Sprintln(info))
	}
}
